package com.ls.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ls.blog.dto.ResourceDTO;
import com.ls.blog.entity.Resource;
import com.ls.blog.entity.RoleResource;
import com.ls.blog.mapper.ResourceMapper;
import com.ls.blog.mapper.RoleResourceMapper;
import com.ls.blog.service.ResourceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ls.blog.service.RoleResourceService;
import com.ls.blog.utils.ObjectUtils;
import com.ls.blog.utils.RedisUtil;
import com.ls.blog.vo.ResourceV0;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.stream.Collectors;

import static com.ls.blog.common.consts.RedisKeyConst.RESOURCE_CACHE;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author lishun
 * @since 2022-01-17
 */
@Service
@Slf4j
public class ResourceServiceImpl extends ServiceImpl<ResourceMapper, Resource> implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;

    @Autowired
    private RoleResourceService roleResourceService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public List<ResourceDTO> listResourceDTO() {
        // 从缓存中拿
        List<?> resourceList = redisUtil.lGet("resourceList", 0, -1);
        if (Objects.isNull(resourceList)||resourceList.size()==0){
            // 避免缓存击穿，突然多个线程查询数据库
            synchronized (ResourceServiceImpl.class){
                resourceList = redisUtil.lGet("resourceList", 0, -1);
                if (Objects.isNull(resourceList) || resourceList.size()==0){
                    resourceList = resourceMapper.listResourceDTO();
                    if (Objects.nonNull(resourceList)){
                        redisUtil.lSetList("resourceList", (List<Object>) resourceList);
                    }
                }
            }
        }
        return ObjectUtils.copyList(resourceList,ResourceDTO.class);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void importSwagger() {
        // 删除所有资源
        this.remove(null);
        roleResourceService.remove(null);
        List<Resource> resourceList = new ArrayList<>();
        Map<String, Object> data = restTemplate.getForObject("http://localhost:8080/v2/api-docs", Map.class);
        // 获取所有模块
        List<Map<String, String>> tagList = (List<Map<String, String>>) data.get("tags");
        tagList.forEach(item -> {
            Resource resource = Resource.builder()
                    .resourceName(item.get("name"))
                    .isAnonymous(0)
                    .build();
            resourceList.add(resource);
        });
        this.saveBatch(resourceList);
        Map<String, Integer> permissionMap = resourceList.stream()
                .collect(Collectors.toMap(Resource::getResourceName, Resource::getId));
        resourceList.clear();
        // 获取所有接口
        Map<String, Map<String, Map<String, Object>>> path = (Map<String, Map<String, Map<String, Object>>>) data.get("paths");
        path.forEach((url, value) -> value.forEach((requestMethod, info) -> {
            String permissionName = info.get("summary").toString();
            List<String> tag = (List<String>) info.get("tags");
            Integer parentId = permissionMap.get(tag.get(0));
            Resource resource = Resource.builder()
                    .resourceName(permissionName)
                    .url(url.replaceAll("\\{[^}]*\\}", "*"))
                    .parentId(parentId)
                    .requestMethod(requestMethod.toUpperCase())
                    .isAnonymous(0)
                    .build();
            resourceList.add(resource);
        }));
        roleResourceService.remove(null);

        this.saveBatch(resourceList);

        // 保存管理员，避免都无法登录
        List<RoleResource> list = resourceList.stream().map(resource -> {
            RoleResource roleResource = new RoleResource();
            roleResource.setRoleId(1);
            roleResource.setResourceId(resource.getId());
            return roleResource;
        }).collect(Collectors.toList());
        roleResourceService.saveBatch(list);
        redisUtil.del(RESOURCE_CACHE);
    }

    @Override
    public List<ResourceDTO> listOpt() {
        List<Resource> resourceList = this.list(new LambdaQueryWrapper<Resource>()
                .select(Resource::getId, Resource::getResourceName,Resource::getParentId)
        );
        return coverChildren(resourceList);
    }

    public List<ResourceDTO> coverChildren (List<Resource> resourceList){
        List<ResourceDTO> resourceDTOList = resourceList.stream()
                .map(item -> ObjectUtils.copyObject(item, ResourceDTO.class))
                .collect(Collectors.toList());
        // 获得父级资源
        List<ResourceDTO> parent = resourceDTOList.stream()
                .filter(resource -> Objects.isNull(resource.getParentId()))
                .collect(Collectors.toList());
        // 获得儿子
        resourceDTOList.removeAll(parent);
        // 分类儿子
        Map<Integer, List<ResourceDTO>> childrenMap = resourceDTOList
                .stream()
                .collect(Collectors.groupingBy(ResourceDTO::getParentId));

        return parent.stream().map(resourceDTO -> {
            if (childrenMap.containsKey(resourceDTO.getId())){
                resourceDTO.setChildren(childrenMap.get(resourceDTO.getId()));
            }
            return resourceDTO;
        }).collect(Collectors.toList());
    }

    @Override
    public List<Integer> listByRoleId(Integer id) {
        LambdaQueryWrapper<RoleResource> queryWrapper = new LambdaQueryWrapper<RoleResource>()
                .select(RoleResource::getResourceId)
                .eq(RoleResource::getRoleId,id);
        List<Integer> list = roleResourceService
                .list(queryWrapper)
                .stream()
                .map(RoleResource::getResourceId)
                .collect(Collectors.toList());
        return list;
    }

    @Override
    @Transactional
    public void updateRoleResource(ResourceV0 resourceV0) {
        // 删除中间表全表
        roleResourceService.remove(new LambdaQueryWrapper<RoleResource>().eq(RoleResource::getRoleId,resourceV0.getRoleId()));
        // 封装中间表
        List<RoleResource> roleResources = resourceV0.getIds().stream().map(item -> {
            return RoleResource.builder().roleId(resourceV0.getRoleId()).resourceId(item).build();
        }).collect(Collectors.toList());
        redisUtil.del(RESOURCE_CACHE);
        roleResourceService.saveBatch(roleResources);
    }

    @Override
    public List<ResourceDTO> listResourceShow() {
        return coverChildren(this.list());
    }

    @Override
    public void updateIsAnonymous(ResourceV0 resourceV0) {
        this.updateById(ObjectUtils.copyObject(resourceV0,Resource.class));
        redisUtil.del("resourceList");
    }
}

